package tools.oma;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class omaUtils {

	static String sep="\t";
	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		if(args.length>0){
			if(args[0].equals("splitDB")&&args.length==3){
				splitDB(args[1],args[2]);
			}else if(args[0].equals("convertFormat")&&args.length==2){
				convertFormat(args[1]);
			}else if(args[0].equals("createTree")&&args.length==3){
				createTree(args[1],args[2]);
			}else if(args[0].equals("consenseCluster")&&args.length>3){
				consenseCluster(args);
			}else if(args[0].equals("splitFile")&&args.length==0){
				//Another method
			}else{
				System.err.println(printHelp());
				System.exit(616);
			}
		}else{
			System.err.println(printHelp());
			System.exit(616);
		}
	}
	public static String printHelp(){
		String help="omaUtils does oma-things\n";
		help+="Usage: omaUtils <cmd> <input>\n";
		help+="splitDB - Splits the DB file with regard to specie\n";
		help+="\t<input> = <db file> <prefix>\n";
		help+="convertFormat - converts the xslt csv output\n";
		help+="\t<input> = <xslt csv file> \n";
		help+="createTree - converts a csv-file (id\\ttChrom) to a tree with the taxa present in the id-list. One branch for each cluster and non-present placed in the root\n";
		help+="\t<input> = <csv-file> <id-list> \n";
		help+="conseseCluster - makes a consensus of a number of csv-files (id\\ttarget-chrom)\n";
		help+="\t<input> = <csv-file> ... <csv-file> \n";
		
		return help;
	}
	
	public static void consenseCluster(String[] args)throws Exception{
		ArrayList<consenseCluster_cluster<String>> clusters= new ArrayList<consenseCluster_cluster<String>>();
		HashMap<String, ArrayList<Integer>> seqs= new HashMap<String, ArrayList<Integer>>();
		ArrayList<Integer> done;
		ArrayList<consenseCluster_cluster<String>> toAdd;
		TreeSet<String> tmp,cluster;
		HashMap<String, TreeSet<String>> novel;
		for(int i=1;i<args.length;i++){
			System.err.println(args[i]+"\t"+clusters.size());
			novel=consenseCluster_read(args[i]);
			for (String key : novel.keySet()) {
				System.err.println("\t"+key+"\t"+novel.get(key).size());
				cluster= new TreeSet<String>(novel.get(key));
				if(cluster.size()>1){
					done=new ArrayList<Integer>();
					for (String seq : cluster) {
						if(seqs.containsKey(seq)){
							//iterate through clusters
							toAdd= new ArrayList<consenseCluster_cluster<String>>();
							ArrayList<Integer> s= new ArrayList<Integer>(seqs.get(seq));
							for (Integer test : s) {
								if(!done.contains(test)){
									done.add(test);
									tmp= new TreeSet<String>(cluster);
									tmp.retainAll(clusters.get(test).getCluster());
									if(tmp.size()>1){
										if(tmp.size()==clusters.get(test).size()){
											//increase support by one
											clusters.get(test).increaseSupport(1);
										}else{
											//check if the cluster is already found
											boolean add=true;
											ArrayList<Integer> s1= new ArrayList<Integer>(seqs.get(seq));
											for (Integer t1 : s1) {
												if(clusters.get(t1).equals(tmp)){
													add=false;
													if(!done.contains(t1)){
														clusters.get(t1).increaseSupport(1);
														done.add(t1);
													}
													break;
												}
											}
											if(add){
												for(String seq1 : tmp){
													if(!seqs.containsKey(seq1)){
														seqs.put(seq1, new ArrayList<Integer>());
													}
													seqs.get(seq1).add(clusters.size());
												}
												done.add(clusters.size());
												clusters.add(new consenseCluster_cluster<String>(tmp,clusters.get(test).getSupport()+1));
											}
											
											
											
//											boolean n=true;
//											for (consenseCluster_cluster<String> b : toAdd) {
//												if(b.equals(tmp)){
//													n=false;
//													break;
//												}
//											}
//											if(n){
//													
//											}
											//create new cluster, this one is smaller... larger clusters will be added by the extra sequences
//											for(String seq1 : tmp){
//												if(!seqs.containsKey(seq1)){
//													seqs.put(seq1, new ArrayList<Integer>());
//												}
//												seqs.get(seq1).add(clusters.size());
//											}
//											done.add(clusters.size());
//											clusters.add(new consenseCluster_cluster<String>(tmp,clusters.get(test).getSupport()+1));
										}
									}
								}
							}
							//add new clusters
							for (consenseCluster_cluster<String> ccc : toAdd) {
								boolean add=true;
								for (Integer test : s) {
									if(clusters.get(test).equals(ccc)){
										add=false;
										if(!done.contains(test)){
											clusters.get(test).increaseSupport(1);
											done.add(test);
										}
										break;
									}
								}
								if(add){
									for(String seq1 : ccc.getCluster()){
										if(!seqs.containsKey(seq1)){
											seqs.put(seq1, new ArrayList<Integer>());
										}
										seqs.get(seq1).add(clusters.size());
									}
									done.add(clusters.size());
									clusters.add(ccc);
								}
							}
						}else{
							//add new 
							for (String seq1 : cluster) {
								if(!seqs.containsKey(seq1)){
									seqs.put(seq1, new ArrayList<Integer>());
								}
								seqs.get(seq1).add(clusters.size());
							}
							done.add(clusters.size());
							clusters.add(new consenseCluster_cluster<String>(cluster));
						}
					}
				}
			}
		}
		//print result
		for (int i=0;i<clusters.size();i++) {
			int t=clusters.get(i).getSupport();
			for (String seq : clusters.get(i).getCluster()) {
				System.out.println(seq+sep+i+sep+t);
			}
		}
	}
	
	public static boolean consenseCluster_equals(TreeSet<String> a,TreeSet<String> b){
		return a.size()==b.size()&&a.containsAll(b);
	}
	
	public static HashMap<String, TreeSet<String>> consenseCluster_read(String file)throws Exception{
		HashMap<String, TreeSet<String>> clusters= new HashMap<String, TreeSet<String>>();
		BufferedReader in= new BufferedReader(new FileReader(file));
		String[] l;
		for(String s=in.readLine();s!=null;s= in.readLine()){
			l=s.split("\t");
			if(l.length>1){
				if(!clusters.containsKey(l[1])){
					clusters.put(l[1],new TreeSet<String>());
				}
				clusters.get(l[1]).add(l[0]);
			}
		}
		return clusters;
	}
	
	
	public static void createTree(String csvfile, String idList)throws Exception{
		ArrayList<String> ids=new ArrayList<String>();
		HashMap<String, ArrayList<String>> groups = new HashMap<String, ArrayList<String>>();
		String[] l;
		BufferedReader in= new BufferedReader(new FileReader(idList));
		for(String s= in.readLine();s!=null;s= in.readLine()){
			ids.add(s);
		}
		in= new BufferedReader(new FileReader(csvfile));
		for(String s= in.readLine();s!=null;s= in.readLine()){
			l=s.split("\t");
			if(l.length>1){
				if(!groups.containsKey(l[1])){
					groups.put(l[1], new ArrayList<String>());
				}
				groups.get(l[1]).add(l[0]);
				ids.remove(l[0]);
			}
		}
		
		//print
		System.out.print("(");
		//print groups
		boolean first=true;
		for (String key : groups.keySet()) {
			if(first){
				System.out.print(createTree_printGroup(groups.get(key)));
				first=false;
			}else{
				System.out.print(", "+createTree_printGroup(groups.get(key)));
			}
		}
		//print missing
		for (String id : ids) {
			if(first){
				System.out.print(id);
				first=false;
			}else{
				System.out.print(", "+id);
			}
		}
		System.out.println(");");
	}
	
	private static String createTree_printGroup(ArrayList<String> list){
		String ret="";
		if(list.size()>1){
			ret="("+list.get(0);
			for(int i=1; i<list.size();i++){
				ret+=", "+list.get(i);
			}
			ret+=")";
		}else{
			ret=list.get(0);
		}
		return ret;
	}
	
	public static void convertFormat(String file)throws Exception{
		BufferedReader in= new BufferedReader(new FileReader(file));
		in.readLine();
		in.readLine();
		String[] l,l2;
//		System.out.println("id\tgenomic start\tgenomic end\tchrom\tOG\tAC\tVP");
		for(String s=in.readLine();s!=null;s=in.readLine()){
			
			l = s.split("\t");
			if (l.length>6){
				//			System.out.println(l[5].replaceAll("[join|complement|(|)]", ""));
				l2 = l[5].replaceAll("[a-zA-Z|(|)]", "").replace('.',',').split(",");
				//			System.out.println(l2.length);
				//
				System.out.println(l[0] + convertFormat_pad(l[1]) + sep + l2[0] + sep + l2[l2.length - 1] + sep + l[4] + sep + l[2] + sep + l[3] + sep + l[6]);
			}
		}
	}
	
	private static String convertFormat_pad(String s){
		for(;s.length()<5;){
			s="0"+s;
		}
		return s;
	}
	
	public static void splitDB(String dbfile, String prefix)throws Exception{
		BufferedReader in= new BufferedReader(new FileReader(dbfile));
		HashMap<String, BufferedWriter> outs= new HashMap<String, BufferedWriter>();
		BufferedWriter out;
		String specie;
		for(String s=in.readLine();s!=null;s=in.readLine()){
			if(s.length()>4&&s.startsWith("<E>")){
				specie=s.substring(7, 12);
				if(!outs.containsKey(specie)){
					out= new BufferedWriter(new FileWriter(prefix+specie+".xml"));
					out.write("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"All_to_tab.xsl\"?>\n<db>\n");
					outs.put(specie, out);
				}
				outs.get(specie).write(s+"\n");
			}
		}
		for(String s : outs.keySet()){
			out= outs.get(s);
			out.write("</db>\n");
			out.close();
		}
	}
}
